Macアプリ、Obj-CでのNSDictionary略記法のダークなタイミング
概要
NSDictionaryの略記法使うと、理由不明のエラーが出るケース。
ずーっと自分のライブラリ疑ってたんだけど、違った。
下記ケースで、NSDictionaryの生成略記法 @{} での辞書生成が悪さをする。
ちなみにMac版アプリだけで発生を確認している。
iOS用だと、実機/シミュレータともに発生していない。
環境
Xcode 4.6.2
Mac OS 10.8.3
ARC:あり
Mac用アプリ
症状
IMPを指定してのメソッド実行で、そのメソッド内で
NSDictionary * dict = @{@"key":@"value"};
とすると、生成時は死なないが、メソッドを抜ける瞬間に
EXEC_BAD_ACCESS(code=12,address=0x0)
が発生する。
発生確率は10/100回、10%くらい。Jenkins見てる限りはそんな感じ。
環境差とかはわからん。
サンプルコード
#import "AppDelegate.h"
@implementation AppDelegate {
SEL m_receiver;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
m_receiver = @selector(receiver:);
// Insert code here to initialize your application
IMP func = [self methodForSelector:m_receiver];
(* func)(self, m_receiver, aNotification);
}
- (void) receiver:(NSNotification * )notif {
NSLog(@"hereComes %@", notif);
NSDictionary * dict = @{@"key":@"val"};//←
}
@end
←のあるラインで、この行を通過後、
(* func)(self, m_receiver, aNotification);
この行を抜けるタイミングでエラーになる。
サンプルプロジェクト
githubに上げといた。
https://github.com/sassembla/DummyProject
100回Jenkinsさんでまわして発生するか試してみた条件など
・ARCをオフにすると発生しない
・略記法@{}ではなく、通常記法だと発生しない
・辞書の内容を空にすると発生しない
NSDictionary * dict = @{}; だと、発生しなかった。
・switch文に入れ、通過しないcaseの中にあっても発生した
ぶっちゃけ原因追及に時間がかかった理由はこれで、
switch文、しかもその時点では内容が存在するcaseを通過しない、という条件にも関わらず、発生している。
switch文を加えた、下記コードでも問題が発生する。
- (void) receiver:(NSNotification * )notif {
NSLog(@"hereComes %@", notif);
int a = 0;
switch (a) {
case 0:{
break;
}
case -1:{
NSDictionary * dict = @{@"key":@"val"};//←
break;
}
default:
break;
}
}
aが0なのは自明だし、switch文で0に飛び込むので、まーなんも起こらねーだろと思ったら、発生した。
略記法の内容生成自体はswitch文生成と一緒に行われてるんだろうな。
実際にallocするかどうかは別として。
発生確率を上げる方法
特に思いついていないが、複数、辞書の初期化コードを書くとかしても、発生率に変化は無かった、、とおもう。たぶん。
誰かのハマりの助けになれたらと思うが。
なんかあったらgithubのIssueでもください。